feat(core): Support array attributes for spans, logs and metrics#20427
feat(core): Support array attributes for spans, logs and metrics#20427nicohrubec wants to merge 27 commits intodevelopfrom
Conversation
Relay's wire contract (AttributeType enum in relay-event-schema) defines
exactly five `type:` tags: boolean, integer, double, string, array.
The SDK's AttributeTypeMap previously declared typed array variants
(`string[]`, `integer[]`, etc.) that Relay does not recognize - these
were never actually emitted because the runtime serializer only handled
primitives, so array-valued attributes silently dropped.
This change:
- Collapses the four `x[]` variants in AttributeTypeMap into a single
`array` variant whose value is `Array<string> | Array<number> | Array<boolean>`.
- Extends getTypedAttributeValue to auto-detect homogeneous primitive
arrays and emit `{type: 'array', value: [...]}`.
- Adds an isHomogeneousPrimitiveArray guard so mixed-type and nested
arrays remain unsupported (dropped by default, stringified under
the fallback path).
- Updates tests to cover the new typed-array path (including empty
arrays, unit preservation, and mixed-type drop/stringify).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
size-limit report 📦
|
Arrays that were previously dropped by the serializer now ship as native array attributes (`type: 'array'`). Update the affected integration test expectations and bump size-limit thresholds for the five bundle scenarios whose gzipped/uncompressed sizes grew from the new serializer logic. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop the size-limit increases for the five bundle scenarios that grew from adding homogeneous primitive array support. Test expectation updates from the previous commit stay. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Re-apply the size-limit bumps needed to account for the new homogeneous-primitive-array detection logic. Five scenarios grew past their thresholds: - @sentry/browser (incl. Metrics & Logs): 28 → 29 KB - CDN Bundle (incl. Logs, Metrics): 30 → 31 KB - CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed: 258.5 → 259 KB - CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed: 268 → 269 KB - CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed: 271.5 → 272 KB Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…72 KB Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| } | ||
| } | ||
|
|
||
| function isHomogeneousPrimitiveArray(arr: unknown): arr is Array<string> | Array<number> | Array<boolean> { |
There was a problem hiding this comment.
q: Was it previously decided that SDKs have to guarantee homogeneity? Just wondering if we really have to iterate over the entire array for every array.
There was a problem hiding this comment.
Jap fair question, we are still discussing that one 😅
There was a problem hiding this comment.
Talked to ingest: We don't need any SDK-side runtime validation.
|
Converting back to draft until we have a definitive answer for SDK validation. |
|
@chargome @mydea I talked to Ingest last week and the outcome was that we don't need any SDK-side runtime validation for user-set arrays on attributes. Relay will just drop any attributes with non-conforming arrays set as values. Based on that I simplified the PR, should be good for another look. The frontend still doesn't display these properly yet though. I will make sure to properly test this e2e before merging after the FE is ready. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f896f3a. Configure here.
| */ | ||
| function getTypedAttributeValue(value: unknown): TypedAttributeValue | void { | ||
| if (Array.isArray(value) && value.length !== 0) { | ||
| return { value, type: 'array' }; |
There was a problem hiding this comment.
Mixed-type array console parameters silently dropped by Relay
Medium Severity
The getTypedAttributeValue function now converts all non-empty arrays to { type: 'array' } before the stringify fallback path is reached. This means SDK-internal sentry.message.parameter.X attributes created by createConsoleTemplateAttributes from mixed-type console args (e.g. console.log('Array:', [1, 2, 3, 'string'])) are now sent as array attributes instead of being stringified. Since Relay drops non-homogeneous arrays, these template parameters will be silently lost — a regression from the previous behavior where they were preserved as stringified values. The body text is unaffected, but structured template parameter data is lost for mixed-type arrays.
Reviewed by Cursor Bugbot for commit f896f3a. Configure here.
There was a problem hiding this comment.
this is basically what I described in the PR description, we can discuss it but I think this is a tradeoff we have to make. don't think we can really solve this unless we do runtime inspection of the types of elements in arrays
| export type Attributes = Record<string, TypedAttributeValue>; | ||
|
|
||
| export type AttributeValueType = string | number | boolean | Array<string> | Array<number> | Array<boolean>; | ||
| export type AttributeValueType = string | number | boolean | Array<unknown>; |
There was a problem hiding this comment.
h: Do we really want Array<unknown>? Every change that follows would be breaking from here on.
There was a problem hiding this comment.
Narrowed it down again
| value: expect.any(Number), | ||
| }, | ||
| // TODO: 'device.archs' is set but arrays are not yet serialized in span attributes | ||
| 'device.archs': { |
There was a problem hiding this comment.
Thanks for pulling this one in.
| 'integer[]': Array<number>; | ||
| 'double[]': Array<number>; | ||
| 'boolean[]': Array<boolean>; | ||
| array: Array<string> | Array<number> | Array<boolean>; |
There was a problem hiding this comment.
q: Would be BigInt supported as well? I think this is a broader question actually
There was a problem hiding this comment.
Mhm not sure. I assume relay enforces some number maximum but no idea what that is.
logaretm
left a comment
There was a problem hiding this comment.
@nicohrubec Do u think it is worth warning in debug if we detect non-homogenous attributes in the array?
Just to ease detecting this for the end user.
| * https://github.com/getsentry/sentry-javascript/pull/18165 | ||
| */ | ||
| function getTypedAttributeValue(value: unknown): TypedAttributeValue | void { | ||
| if (Array.isArray(value) && value.length !== 0) { |
There was a problem hiding this comment.
@nicohrubec q: what happens in empty arrays? are they still stringified?
There was a problem hiding this comment.
as discussed I'll switch that logic to early return for empty arrays so they get dropped for both fallback/non-fallback paths. the way it is right now if fallback is enabled we send a stringified empty array if the fallback is on
There was a problem hiding this comment.
actually after further discussion we won't be dropping empty arrays (independent of fallback on/off)
Now that array attributes are serialized, `device.archs` is no longer dropped — uncomment and enable the assertions in integration tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>



Adds array attribute support for spans, logs, and metrics. Relay only supports primitive homogeneous arrays (all elements have the same primitive type). However, any attributes with non-conforming arrays will be dropped by Relay, so there is no need for runtime validation on the SDK end.
This change as is comes with a behavioral change for user-defined logs and metrics. If users previously set array attributes for logs/metrics then these were previously sent to Sentry stringified, now these will be sent as arrays. After discussion with product teams we also decided not to drop empty arrays.
Note: the Sentry frontend doesn't render array attributes correctly yet, but that's expected to land soon.
Blocks #20428
Closes #20651
Closes #20438